﻿using System;
using Box2DX.Common;

namespace Expression.Samples.Physics
{
	public class SimulatorContext
	{
		private Vector2 screenTopLeft;
		private Vector2 screenBottomRight;
		private Vector2 worldTopLeft;
		private Vector2 worldBottomRight;

		public SimulatorContext(Vector2 screenTopLeft, Vector2 screenBottomRight, Vector2 worldTopLeft, Vector2 worldBottomRight)
		{
			this.screenTopLeft = screenTopLeft;
			this.screenBottomRight = screenBottomRight;
			this.worldTopLeft = worldTopLeft;
			this.worldBottomRight = worldBottomRight;
		}

		public Vector2 ScreenToWorld(System.Windows.Point screen) {
			return ConvertCoordinates((float)screen.X, (float)screen.Y, this.screenTopLeft, this.screenBottomRight, this.worldTopLeft, this.worldBottomRight, true);
		}

		public System.Windows.Point WorldToScreen(Vector2 world) {
			Vector2 value = ConvertCoordinates(world.X, world.Y, this.worldTopLeft, this.worldBottomRight, this.screenTopLeft, this.screenBottomRight, true);

			return new System.Windows.Point(value.X, value.Y);
		}

		public Vector2 ScreenSizeToWorldSize(System.Windows.Size size) {
			return ConvertSize(new Vector2((float)size.Width, (float)size.Height), this.screenTopLeft, this.screenBottomRight, this.worldTopLeft, this.worldBottomRight, true);
		}

		public Vector2 ScreenSizeToWorldSize(System.Windows.Point size) {
			return ConvertSize(new Vector2((float)size.X, (float)size.Y), this.screenTopLeft, this.screenBottomRight, this.worldTopLeft, this.worldBottomRight, true);
		}

		public System.Windows.Size WorldSizeToScreenSize(Vector2 size) {
			Vector2 result = ConvertSize(size, this.worldTopLeft, this.worldBottomRight, this.screenTopLeft, this.screenBottomRight, true);
			return new System.Windows.Size(result.X, result.Y);
		}

		private float ScreenWidth {
			get { return (this.screenBottomRight - this.screenTopLeft).X; }
		}

		private float ScreenHeight {
			get { return (this.screenBottomRight - this.screenTopLeft).Y; }
		}

		private Vector2 ConvertCoordinates(float x, float y, Vector2 topLeft1, Vector2 bottomRight1, Vector2 topLeft2, Vector2 bottomRight2, bool invertY)
		{
			float w1 = bottomRight1.X - topLeft1.X;
			float h1 = bottomRight1.Y - topLeft1.Y;
			float u = (x - topLeft1.X) / w1;
			float v = (y - topLeft1.Y) / h1;
			if (invertY)
			{
				v = 1 - v;
			}
			Vector2 p = new Vector2();
			p.X = ((1.0f - u) * topLeft2.X) + (u * bottomRight2.X);
			p.Y = ((1.0f - v) * topLeft2.Y) + (v * bottomRight2.Y);
			return p;
		}

		private Vector2 ConvertSize(Vector2 size, Vector2 topLeft1, Vector2 bottomRight1, Vector2 topLeft2, Vector2 bottomRight2, bool invertY)
		{
			float w1 = bottomRight1.X - topLeft1.X;
			float h1 = bottomRight1.Y - topLeft1.Y;
			float w2 = bottomRight2.X - topLeft2.X;
			float h2 = bottomRight2.Y - topLeft2.Y;
			float rw = (w2 / w1);
			float rh = (invertY ? -1 : 1) * (h2 / h1);
			Vector2 p = new Vector2();
			p.X = size.X * rw;
			p.Y = size.Y * rh;
			return p;
		}
	}
}
